home *** CD-ROM | disk | FTP | other *** search
/ Large Pack of OldSkool DOS MOD Trackers / buzzmachines_massive.exe / Dev / CyanPhase DTMF-1.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-08-26  |  10.8 KB  |  539 lines

  1. // A tiny and simple generator
  2. // Version 1.1 - click fix
  3. // This demonstrates how to use fast sine coefs (useful only >40Hz)
  4. // CyanPhase DTMF-1
  5. // Copyright 2000 CyanPhase aka Edward L. Blake
  6. // Enjoy
  7.  
  8. #include <string.h>
  9. #include <stdlib.h>
  10. #include <math.h>
  11. #include <float.h>
  12. #include "../MachineInterface.h"
  13. #include "../dsplib/dsplib.h"
  14.  
  15. #pragma optimize ("awy", on)
  16.  
  17. float const pi2 = 2 * PI;
  18.  
  19. // DTMF Chart
  20. // 1 - 1 - 697Hz + 1209Hz
  21. // 2 - 2 - 697Hz + 1336Hz
  22. // 3 - 3 - 697Hz + 1477Hz
  23. // 4 - 4 - 770Hz + 1209Hz
  24. // 5 - 5 - 770Hz + 1336Hz
  25. // 6 - 6 - 770Hz + 1477Hz
  26. // 7 - 7 - 852Hz + 1209Hz
  27. // 8 - 8 - 852Hz + 1336Hz
  28. // 9 - 9 - 852Hz + 1477Hz
  29. // A - * - 941Hz + 1209Hz
  30. // 0 - 0 - 941Hz + 1336Hz
  31. // B - # - 941Hz + 1477Hz
  32.  
  33.  
  34. #define MIN_AMP        (0.0001 * (32768.0 / 0x7fffffff))
  35.  
  36. CMachineParameter const paraNumber = {
  37.     pt_byte,
  38.     "Dial Number",
  39.     "Dial Number",
  40.     0,
  41.     11,
  42.     0xFF,
  43.     0,
  44.     0
  45. };
  46.  
  47. CMachineParameter const paraSustain = {
  48.  
  49.     pt_byte,
  50.     "Sustain",
  51.     "Sustain",
  52.     0,
  53.     0xFE,
  54.     0xFF,
  55.     MPF_STATE,
  56.     40
  57. };
  58.  
  59. CMachineParameter const paraTwist = {
  60.     pt_byte,
  61.     "Twist",
  62.     "Twist in dB",
  63.     0,
  64.     40,
  65.     0xFF,
  66.     MPF_STATE,
  67.     0
  68. };
  69.  
  70. CMachineParameter const paraVolume = {
  71.     pt_byte,
  72.     "Volume",
  73.     "Volume",
  74.     0,
  75.     0xFE,
  76.     0xFF,
  77.     MPF_STATE,
  78.     0xC0
  79. };
  80.  
  81. CMachineParameter const *pParameters[] = {
  82.     ¶Number,
  83.     ¶Sustain,
  84.     ¶Twist,
  85.     ¶Volume
  86. };
  87.  
  88. CMachineAttribute const attrAttack =
  89. {
  90.     "Analog Attack in ms",
  91.     1,
  92.     1000,
  93.     10
  94. };
  95.  
  96. CMachineAttribute const attrRelease =
  97. {
  98.     "Analog Release in ms",
  99.     1,
  100.     1000,
  101.     20
  102. };
  103.  
  104. CMachineAttribute const *pAttributes[] =
  105. {
  106.     &attrAttack,
  107.     &attrRelease,
  108. };
  109.  
  110. #pragma pack(1)
  111.  
  112. class gvals
  113. {
  114. public:
  115.     byte number;
  116.     byte sustain;
  117.     byte twist;
  118.     byte volume;
  119. };
  120.  
  121. class avals
  122. {
  123. public:
  124.     int attack;
  125.     int release;
  126. };
  127.  
  128. #pragma pack()
  129.  
  130. CMachineInfo const MacInfo =
  131. {
  132.  
  133.     MT_GENERATOR,
  134.     MI_VERSION,
  135.     0,
  136.     0,
  137.     0,
  138.     4,
  139.     0,
  140.     pParameters,
  141.     2,
  142.     pAttributes,
  143.     "CyanPhase DTMF-1",
  144.     "DTMF-1",
  145.     "Edward L. Blake",
  146.     NULL
  147. };
  148.  
  149. class mi;
  150.  
  151. class mi : public CMachineInterface
  152. {
  153. public:
  154.     mi();
  155.     virtual ~mi();
  156.     virtual void Init(CMachineDataInput * const pi);
  157.     virtual void Tick();
  158.     virtual bool Work(float *psamples, int numsamples, int const mode);
  159.     virtual char const *mi::DescribeValue(int const param, int const value);
  160.     virtual void DialThatNumber(int number);
  161.     virtual void Stop();
  162.  
  163. public:
  164.     gvals gval;
  165.     avals aval;
  166.     
  167.     // FastSine 1
  168.     float tone1coeff, tone1value1, tone1value2, tone1amp;
  169.     // FastSine 2
  170.     float tone2coeff, tone2value1, tone2value2, tone2amp;
  171.     
  172.     float volume, twist, counter, counterstop, counterattack;
  173.     float counterrelease, attackrate, releaserate, aramp;
  174.     int ison;
  175. };
  176.  
  177. DLL_EXPORTS
  178.  
  179. mi::mi()
  180. {
  181.     GlobalVals = &gval;
  182.     AttrVals = (int *)&aval;
  183. }
  184.  
  185. mi::~mi() { }
  186.  
  187. void mi::Init(CMachineDataInput * const pi)
  188. {
  189.     tone1value1 = 0.0f;
  190.     tone1value2 = 0.0f;
  191.     tone1coeff = 0.0f;
  192.     tone1amp = 0.0f;
  193.     tone2value1 = 0.0f;
  194.     tone2value2 = 0.0f;
  195.     tone2coeff = 0.0f;
  196.     tone2amp = 0.0f;
  197.  
  198.     ison = 0;
  199.     counter = 0.0f;
  200.     counterstop = 0.0f;
  201.     volume = 0.0f;
  202.     twist = 0.0f;
  203.  
  204.     aramp = 0.0f;
  205.  
  206.     counterattack = 0.0f;
  207.     counterrelease = 0.0f;
  208.     attackrate = 0.0f;
  209.     releaserate = 0.0f;
  210.  
  211.  
  212.     // I find that adding a copy of the mi::Tick to mi::Init
  213.     // yields a better chance that parameters will load correctly
  214.     // on song load
  215.  
  216.     if (gval.sustain != 0xFF) {
  217.         counterstop = (gval.sustain * pMasterInfo->SamplesPerSec) / 100.0f;
  218.     };
  219.  
  220.     if (gval.twist != 0xFF) {
  221.  
  222.         twist = pow(10.0f,(gval.twist / 10.0f));
  223.         tone2amp = volume + twist; // Tone 2 is always the highest frequency
  224.     };
  225.  
  226.     if (gval.volume != 0xFF) {
  227.         volume = gval.volume * 80.0f;
  228.         tone1amp = volume;
  229.         tone2amp = volume + twist; // Tone 2 is always the highest frequency
  230.     };
  231.  
  232.     if (gval.number != 0xFF) DialThatNumber(gval.number);
  233.  
  234.     // Makes sure it doesn't squeak on startup
  235.     ison = 0;
  236. }
  237.  
  238.  
  239. // This is the procedure that actually initializes
  240. // the fast sine variables
  241. void mi::DialThatNumber(int number) {
  242.     float f = 0.0f;
  243.  
  244.     ison = 1;
  245.     aramp = 0.0f;
  246.     counter = 0.0f;
  247.  
  248.     counterattack = ((float)aval.attack / 1000.0f) * pMasterInfo->SamplesPerSec;
  249.     counterrelease = ((float)aval.release / 1000.0f) * pMasterInfo->SamplesPerSec;
  250.     attackrate = 1.0f / counterattack;
  251.     releaserate = 1.0f / counterrelease;
  252.  
  253.     switch (number) {
  254.     case 0: // 0
  255.  
  256.         // First Tone (941Hz)
  257.         f = 941.0f * pi2/pMasterInfo->SamplesPerSec;
  258.         tone1coeff = 2.0f * cos(f);
  259.         tone1value1 = sin(0.0f);
  260.         tone1value2 = sin(-f + 0.0f);
  261.  
  262.         // Second Tone (1336Hz)
  263.         f = 1336.0f * pi2/pMasterInfo->SamplesPerSec;
  264.         tone2coeff = 2.0f * cos(f);
  265.         tone2value1 = sin(0.0f);
  266.         tone2value2 = sin(-f + 0.0f);
  267.  
  268.         break;
  269.  
  270.     case 1: // 1
  271.  
  272.         // First Tone (697Hz)
  273.         f = 697.0f * pi2/pMasterInfo->SamplesPerSec;
  274.         tone1coeff = 2.0f * cos(f);
  275.         tone1value1 = sin(0.0f);
  276.         tone1value2 = sin(-f + 0.0f);
  277.  
  278.         // Second Tone (1209Hz)
  279.         f = 1209.0f * pi2/pMasterInfo->SamplesPerSec;
  280.         tone2coeff = 2.0f * cos(f);
  281.         tone2value1 = sin(0.0f);
  282.         tone2value2 = sin(-f + 0.0f);
  283.         break;
  284.  
  285.     case 2: // 2
  286.  
  287.         // First Tone (697Hz)
  288.         f = 697.0f * pi2/pMasterInfo->SamplesPerSec;
  289.         tone1coeff = 2.0f * cos(f);
  290.         tone1value1 = sin(0.0f);
  291.         tone1value2 = sin(-f + 0.0f);
  292.  
  293.         // Second Tone (1336Hz)
  294.         f = 1336.0f * pi2/pMasterInfo->SamplesPerSec;
  295.         tone2coeff = 2.0f * cos(f);
  296.         tone2value1 = sin(0.0f);
  297.         tone2value2 = sin(-f + 0.0f);
  298.         break;
  299.  
  300.     case 3: // 3
  301.  
  302.         // First Tone (697Hz)
  303.         f = 697.0f * pi2/pMasterInfo->SamplesPerSec;
  304.         tone1coeff = 2.0f * cos(f);
  305.         tone1value1 = sin(0.0f);
  306.         tone1value2 = sin(-f + 0.0f);
  307.  
  308.         // Second Tone (1477Hz)
  309.         f = 1477.0f * pi2/pMasterInfo->SamplesPerSec;
  310.         tone2coeff = 2.0f * cos(f);
  311.         tone2value1 = sin(0.0f);
  312.         tone2value2 = sin(-f + 0.0f);
  313.         break;
  314.  
  315.     case 4: // 4
  316.  
  317.         // First Tone (770Hz)
  318.         f = 770.0f * pi2/pMasterInfo->SamplesPerSec;
  319.         tone1coeff = 2.0f * cos(f);
  320.         tone1value1 = sin(0.0f);
  321.         tone1value2 = sin(-f + 0.0f);
  322.  
  323.         // Second Tone (1209Hz)
  324.         f = 1209.0f * pi2/pMasterInfo->SamplesPerSec;
  325.         tone2coeff = 2.0f * cos(f);
  326.         tone2value1 = sin(0.0f);
  327.         tone2value2 = sin(-f + 0.0f);
  328.         break;
  329.  
  330.     case 5: // 5
  331.  
  332.         // First Tone (770Hz)
  333.         f = 770.0f * pi2/pMasterInfo->SamplesPerSec;
  334.         tone1coeff = 2.0f * cos(f);
  335.         tone1value1 = sin(0.0f);
  336.         tone1value2 = sin(-f + 0.0f);
  337.  
  338.         // Second Tone (1336Hz)
  339.         f = 1336.0f * pi2/pMasterInfo->SamplesPerSec;
  340.         tone2coeff = 2.0f * cos(f);
  341.         tone2value1 = sin(0.0f);
  342.         tone2value2 = sin(-f + 0.0f);
  343.         break;
  344.  
  345.     case 6: // 6
  346.  
  347.         // First Tone (770Hz)
  348.         f = 770.0f * pi2/pMasterInfo->SamplesPerSec;
  349.         tone1coeff = 2.0f * cos(f);
  350.         tone1value1 = sin(0.0f);
  351.         tone1value2 = sin(-f + 0.0f);
  352.  
  353.         // Second Tone (1477Hz)
  354.         f = 1477.0f * pi2/pMasterInfo->SamplesPerSec;
  355.         tone2coeff = 2.0f * cos(f);
  356.         tone2value1 = sin(0.0f);
  357.         tone2value2 = sin(-f + 0.0f);
  358.         break;
  359.  
  360.     case 7: // 7
  361.  
  362.         // First Tone (852Hz)
  363.         f = 852.0f * pi2/pMasterInfo->SamplesPerSec;
  364.         tone1coeff = 2.0f * cos(f);
  365.         tone1value1 = sin(0.0f);
  366.         tone1value2 = sin(-f + 0.0f);
  367.  
  368.         // Second Tone (1209Hz)
  369.         f = 1209.0f * pi2/pMasterInfo->SamplesPerSec;
  370.         tone2coeff = 2.0f * cos(f);
  371.         tone2value1 = sin(0.0f);
  372.         tone2value2 = sin(-f + 0.0f);
  373.         break;
  374.  
  375.     case 8: // 8
  376.  
  377.         // First Tone (852Hz)
  378.         f = 852.0f * pi2/pMasterInfo->SamplesPerSec;
  379.         tone1coeff = 2.0f * cos(f);
  380.         tone1value1 = sin(0.0f);
  381.         tone1value2 = sin(-f + 0.0f);
  382.  
  383.         // Second Tone (1336Hz)
  384.         f = 1336.0f * pi2/pMasterInfo->SamplesPerSec;
  385.         tone2coeff = 2.0f * cos(f);
  386.         tone2value1 = sin(0.0f);
  387.         tone2value2 = sin(-f + 0.0f);
  388.         break;
  389.  
  390.     case 9: // 9
  391.  
  392.         // First Tone (852Hz)
  393.         f = 852.0f * pi2/pMasterInfo->SamplesPerSec;
  394.         tone1coeff = 2.0f * cos(f);
  395.         tone1value1 = sin(0.0f);
  396.         tone1value2 = sin(-f + 0.0f);
  397.  
  398.         // Second Tone (1477Hz)
  399.         f = 1477.0f * pi2/pMasterInfo->SamplesPerSec;
  400.         tone2coeff = 2.0f * cos(f);
  401.         tone2value1 = sin(0.0f);
  402.         tone2value2 = sin(-f + 0.0f);
  403.         break;
  404.  
  405.     case 10: // *
  406.  
  407.         // First Tone (941Hz)
  408.         f = 941.0f * pi2/pMasterInfo->SamplesPerSec;
  409.         tone2coeff = 2.0f * cos(f);
  410.         tone2value1 = sin(0.0f);
  411.         tone2value2 = sin(-f + 0.0f);
  412.  
  413.         // Second Tone (1209Hz)
  414.         f = 1209.0f * pi2/pMasterInfo->SamplesPerSec;
  415.         tone2coeff = 2.0f * cos(f);
  416.         tone2value1 = sin(0.0f);
  417.         tone2value2 = sin(-f + 0.0f);
  418.         break;
  419.  
  420.     case 11: // #
  421.  
  422.         // First Tone (941Hz)
  423.         f = 941.0f * pi2/pMasterInfo->SamplesPerSec;
  424.         tone1coeff = 2.0f * cos(f);
  425.         tone1value1 = sin(0.0f);
  426.         tone1value2 = sin(-f + 0.0f);
  427.  
  428.         // Second Tone (1477Hz)
  429.         f = 1477.0f * pi2/pMasterInfo->SamplesPerSec;
  430.         tone2coeff = 2.0f * cos(f);
  431.         tone2value1 = sin(0.0f);
  432.         tone2value2 = sin(-f + 0.0f);
  433.         break;
  434.     default:
  435.         break;
  436.     }
  437.  
  438. }
  439.  
  440. void mi::Tick()
  441. {
  442.  
  443.     if (gval.sustain != 0xFF) {
  444.         counterstop = (gval.sustain * pMasterInfo->SamplesPerSec) / 100.0f;
  445.     };
  446.  
  447.     if (gval.twist != 0xFF) {
  448.  
  449.         twist = pow(10.0f,(gval.twist / 10.0f));
  450.         tone2amp = volume + twist; // Tone 2 is always the highest frequency
  451.     };
  452.  
  453.     if (gval.volume != 0xFF) {
  454.         volume = gval.volume * 80.0f;
  455.         tone1amp = volume;
  456.         tone2amp = volume + twist; // Tone 2 is always the highest frequency
  457.     };
  458.  
  459.     if (gval.number != 0xFF) DialThatNumber(gval.number);
  460. }
  461.  
  462. bool mi::Work(float *psamples, int numsamples, int const)
  463. {
  464.     float tone1now, tone2now, temp, out;
  465.     int i;
  466.  
  467.     if (ison == 0) return false;
  468.  
  469.     for (i = 0; i < numsamples; i++) {
  470.         counter += 1.0f;
  471.         if (counter < counterattack) { aramp += attackrate; } else
  472.         if (counter > (counterstop - counterrelease)) {
  473.             aramp -= releaserate;
  474.             if (aramp < 0.0f) aramp = 0.0f;
  475.         };
  476.  
  477.         if (counter >= counterstop) { ison = 0; };
  478.  
  479.         tone1now = tone1amp * tone1value1;
  480.         temp = tone1value1;
  481.         tone1value1 = tone1coeff * tone1value1 - tone1value2;
  482.         tone1value2 = temp;
  483.  
  484.         tone2now = tone2amp * tone2value1;
  485.         temp = tone2value1;
  486.         tone2value1 = tone2coeff * tone2value1 - tone2value2;
  487.         tone2value2 = temp;
  488.         
  489.         // That is it!!
  490.         out = tone1now + tone2now;
  491.  
  492.         *psamples = out * aramp;
  493.         psamples++;
  494.     }
  495.     return true;
  496. }
  497.  
  498. void mi::Stop() { ison = 0; }
  499.  
  500. char const *mi::DescribeValue(int const param, int const value)
  501. {
  502.     static char txt[16];
  503.  
  504.     switch(param)
  505.     {
  506.     case 0: // Number
  507.         switch (value)
  508.         {
  509.         case 0: return ("0"); break;
  510.         case 1: return ("1"); break;
  511.         case 2: return ("2"); break;
  512.         case 3: return ("3"); break;
  513.         case 4: return ("4"); break;
  514.         case 5: return ("5"); break;
  515.         case 6: return ("6"); break;
  516.         case 7: return ("7"); break;
  517.         case 8: return ("8"); break;
  518.         case 9: return ("9"); break;
  519.         case 10: return ("*"); break;
  520.         case 11: return ("#"); break;
  521.         default: return NULL; break;
  522.         };
  523.         break;
  524.     case 1: // Sustain
  525.         sprintf(txt,"%.2f s",value / 100.0f);
  526.         return txt;
  527.         break;
  528.     case 2: // Twist
  529.         sprintf(txt,"+%.1f dB",value / 10.0f);
  530.         return txt;
  531.         break;
  532.     case 3:
  533.         return NULL;
  534.  
  535.     default: return NULL;
  536.         break;
  537.     };
  538. }
  539.